home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 3 / Info_Mac_1994-01.iso / Development / Source / Arashi 1.1 Source / For your think c folder / Sound Kit ƒ / SoundKit.c < prev   
Encoding:
C/C++ Source or Header  |  1993-05-26  |  14.6 KB  |  624 lines  |  [TEXT/KAHL]

  1. /*/
  2.      Project Arashi: SoundKit.c
  3.      Major release: Version 1.1, 7/22/92
  4.  
  5.      Last modification: Wednesday, May 26, 1993, 18:49
  6.      Created: Saturday, March 18, 1989, 0:55
  7.  
  8.      Copyright © 1989-1993, Juri Munkki
  9. /*/
  10.  
  11. #define    MAKE_SOUNDs
  12. #define    SOUNDKIT_MAIN
  13. #include <Sound.h>
  14. #include <Retrace.h>
  15. #include "Shuddup.h"
  16. #include <GestaltEqu.h>
  17.  
  18. SndDoubleBufferHeader    SKDouble;
  19. SndChannelPtr            SKChannel;
  20.  
  21. #define    SKBUFFERSIZE    (1024)    /*    Size of double buffering data area.        */
  22. #define    SKBUFFERBYTES    (1024)    /*    Actual amount of sound data in buffer.    */
  23. #define    KHZ11            (0x2B7745D1L)
  24. #define    KHZ22            (0x56EE8BA3L)
  25.  
  26. int            OldVol;                /*    Sound volume at InitSoundKit time.    */
  27. int            NumSounds;            /*    Number of packed sounds.            */
  28. int            OldSound=0;            /*    Change to 1 to use old sound driver.*/
  29.  
  30. /*    Note: OldSound works only if you change it before InitSoundKit.        */
  31.  
  32. Ptr            SKPtr;                /*    Pointer for Sound Kit data.            */
  33. SoundStuff    *Sounds;            /*    Storage for sound info table.        */
  34. FFSynthPtr    SoundBuf;            /*    Our one and only FFSynthRec            */
  35. VVars        Vv;                    /*    Vertical blanking variables            */
  36. long        SKTicks;            /*    Tickcount from Sound Kit VBL.        */
  37.  
  38. /*
  39. >>    If A5 points to a VVars structure, the following macro will become
  40. >>    xx(A5), where xx is the offset into that structure element.
  41. */
  42. #define VBV(field)        ((int) &((VVars *) 0)->field)(A5)
  43.  
  44. /*
  45. >>    SKWorkHorse is used by the SoundManager compatible routines to
  46. >>    fill up a new buffer of 512 sound bytes. It mixes two channels
  47. >>    into one by adding them up.
  48. */
  49. void    SKWorkHorse()
  50. {
  51. asm    {
  52.         move.l    A2,-(sp)
  53.         move.l    VBV(SoundB),A0            ;    Get address of sound buffer
  54.  
  55.         move.w    VBV(CountA),D0            ;    Is channel A active?
  56.         beq.s    @silentone                ;    No
  57.                                         ;    Yes:
  58.         sub.w    #1,VBV(CountA)            ;    Decrement counter
  59.         move.l    VBV(ChanA),A1            ;    Get sound data address
  60.  
  61.         move.w    VBV(CountB),D0            ;    Is channel B active?
  62.         bne.s    @twosounds                ;    Yes
  63.                                         ;    No:
  64.         move.l    #0x40404040,D1            ;    Other channel is silent
  65.     
  66.         moveq.l    #63,D0                    ;    Loop counter.
  67. @vbAloop
  68.         move.l    D1,D2                    ;    Copy silence
  69.         add.l    (A1)+,D2                ;    Add sound to silence
  70.         move.l    D2,(A0)+                ;    Store sound+silence
  71.  
  72.         move.l    D1,D2                    ;    ...
  73.         add.l    (A1)+,D2
  74.         move.l    D2,(A0)+
  75.  
  76.         dbra    D0,@vbAloop
  77.         move.l    A1,VBV(ChanA)            ;    Update sound data pointer
  78.         bra.s    @endvbl                    ;    Return from vbl routine
  79.  
  80. @silentone
  81.         move.w    VBV(CountB),D0            ;    Are both channels silent?
  82.         beq.s    @nosound                ;    Yes
  83.                                         ;    No
  84.         sub.w    #1,VBV(CountB)            ;    Play only channel B.
  85.         move.l    VBV(ChanB),A1            ;    comments same as for
  86.         move.l    #0x40404040,D1            ;    channel A above.
  87.         moveq.l    #63,D0
  88.  
  89. @vbBloop
  90.         move.l    D1,D2
  91.         add.l    (A1)+,D2
  92.         move.l    D2,(A0)+
  93.  
  94.         move.l    D1,D2
  95.         add.l    (A1)+,D2
  96.         move.l    D2,(A0)+
  97.         dbra    D0,@vbBloop
  98.  
  99.         move.l    A1,VBV(ChanB)
  100.         bra.s    @endvbl                    ;    Return from vbl routine
  101. @twosounds
  102.         sub.w    #1,VBV(CountB)            ;    Decrement channel B count
  103.         move.l    VBV(ChanB),A2            ;    A2 = channel B sound data pointer
  104.         move.w    #63,D0                    ;    
  105.  
  106. @vbABloop
  107.         move.l    (A1)+,D1                ;    Get Sound channel A
  108.         add.l    (A2)+,D1                ;    Add channel B
  109.         move.l    D1,(A0)+                ;    Store sound
  110.  
  111.         move.l    (A1)+,D1                ;    Get Sound channel A
  112.         add.l    (A2)+,D1                ;    Add channel B
  113.         move.l    D1,(A0)+                ;    Store sound
  114.  
  115.         dbra    D0,@vbABloop            ;    Loop
  116.         move.l    A1,VBV(ChanA)            ;    Update sound channel A data pointer
  117.         move.l    A2,VBV(ChanB)            ;    Update sound channel B data pointer
  118.         bra.s    @endvbl                    ;    Return from vbl routine
  119. @nosound
  120.         move.l    #0x80808080,D1            ;    Silence
  121.         move.w    #127,D0                    ;    512 bytes of silence.
  122. @silencer
  123.         move.l    D1,(A0)+                ;    Store silence
  124.         dbra    D0,@silencer            ;    loop
  125. @endvbl
  126.         move.l    (sp)+,A2
  127.         return                            ;    Return from vbl routine
  128.     }
  129. }
  130.  
  131. /*
  132. >>    See IM-VI to find out what a DoubleBackRoutine is.
  133. >>    Basically it's just a routine that feeds data to the
  134. >>    sound manager.
  135. */
  136. pascal    void    SKDoubleBackRoutine(chan,buf)
  137. SndChannelPtr    chan;
  138. SndDoubleBuffer    *buf;
  139. {
  140.     register    char    *sdata;
  141.     register    VVars    *VVFrame;
  142.                 char    sounder[512];
  143.     
  144.     buf->dbFlags=dbBufferReady;
  145.     
  146.     VVFrame=(VVars *)buf->dbUserInfo[0];
  147.     VVFrame->SoundB=sounder;
  148.  
  149.     sdata=buf->dbSoundData;
  150.  
  151. asm    {    move.l    A5,-(sp)
  152.         move.l    VVFrame,A5
  153.         bsr        SKWorkHorse
  154.         move.l    (sp)+,A5
  155.  
  156.         lea        sounder,A0
  157.         moveq.l    #127,D0
  158. @loop
  159.         move.b    (A0)+,D1
  160.         move.b    D1,(sdata)+
  161.         move.b    D1,(sdata)+
  162.  
  163.         move.b    (A0)+,D1
  164.         move.b    D1,(sdata)+
  165.         move.b    D1,(sdata)+
  166.  
  167.         move.b    (A0)+,D1
  168.         move.b    D1,(sdata)+
  169.         move.b    D1,(sdata)+
  170.         
  171.         move.b    (A0)+,D1
  172.         move.b    D1,(sdata)+
  173.         move.b    D1,(sdata)+
  174.         
  175.         dbra    D0,@loop
  176.     }
  177. }
  178.  
  179. /*
  180. >>    Setup vertical blanking variables &
  181. >>    install vertical blanking task.
  182. */
  183. void    InstallMyVBL()
  184. {
  185.     register    long    vbltask;
  186.     register    Handle     SystemHand;
  187.     
  188.     asm    {
  189.         lea        @myvbltask,A0        ;    Get address of vbltask
  190.         move.l    A0,vbltask            ;    Store in local variable
  191.         lea        @mybase,A0            ;    Get addr of variable base storage
  192.         lea        Vv,A1                ;    Get addr of Vv record
  193.         move.l    A1,(A0)                ;    Store base in base storage
  194.         }
  195.     
  196.     SystemHand=GetResource(SKRESTYPE,SKSYSJUMP);
  197.     Vv.VBL.qType=vType;                /*    Vertical blanking queue.    */
  198.     Vv.VBL.vblAddr=(ProcPtr) *SystemHand;
  199.     *(long *)(2+*SystemHand)=(long)vbltask;
  200.                                     /*    Address of task                */
  201.     Vv.VBL.vblCount=1;                /*    Every 1/60 seconds            */
  202.     Vv.VBL.vblPhase=0;                /*    0 is ok..                    */
  203.     Vv.TickPtr=&SKTicks;            /*    Faster than TickCount()        */
  204.     VInstall((void *)&Vv.VBL);        /*    Install task in queue        */
  205.     if(0)
  206. asm    {    
  207. @myvbltask
  208.         move.l    A5,-(SP)                ;    Save A5
  209.         move.l    @mybase,A5                ;    Get Vv address into A5
  210.         move.w    #1,VBV(VBL.vblCount)    ;    Call again in 1/60 seconds
  211.         move.l    VBV(TickPtr),A0            ;    Get pointer to private tickcount
  212.         addq.l    #1,(A0)                    ;    Increment private tickcount
  213.  
  214.         clr.l    D0                        ;    Change sound buffer by
  215.         move.w    #256,D0                    ;    setting:
  216.         sub.w    VBV(SoundP),D0            ;    SoundP = 256 - SoundP
  217.         move.w    D0,VBV(SoundP)            ;    Store SoundP for next time
  218.         move.l    D0,VBV(SPar.ioActCount)    ;    Store SoundP into ioActCount
  219.         move.l    VBV(SoundB),A0            ;    Get address of sound buffer
  220.         add.l    D0,A0                    ;    Add SoundP to SoundB
  221.  
  222.         move.w    VBV(CountA),D0            ;    Is channel A active?
  223.         beq.s    @silentone                ;    No
  224.                                         ;    Yes:
  225.         sub.w    #1,VBV(CountA)            ;    Decrement counter
  226.         move.l    VBV(ChanA),A1            ;    Get sound data address
  227.  
  228.         move.w    VBV(CountB),D0            ;    Is channel B active?
  229.         bne.s    @twosounds                ;    Yes
  230.                                         ;    No:
  231.         move.l    #0x40404040,D1            ;    Other channel is silent
  232.         move.l    D1,D2                    ;    Copy silence
  233.         add.l    (A1)+,D2                ;    Add sound to silence
  234.         move.l    D2,(A0)+                ;    Store sound+silence
  235.     
  236.         moveq.l    #22,D0                    ;    Loop counter.
  237. @vbAloop
  238.         move.l    D1,D2                    ;    Copy silence
  239.         add.l    (A1)+,D2                ;    Add sound to silence
  240.         move.l    D2,(A0)+                ;    Store sound+silence
  241.  
  242.         move.l    D1,D2                    ;    ...
  243.         add.l    (A1)+,D2
  244.         move.l    D2,(A0)+
  245.  
  246.         dbra    D0,@vbAloop
  247.         move.l    A1,VBV(ChanA)            ;    Update sound data pointer
  248.         move.l    (SP)+,A5                ;    Restore A5
  249.         rts                                ;    Return from vbl routine
  250.  
  251. @silentone
  252.         move.w    VBV(CountB),D0            ;    Are both channels silent?
  253.         beq.s    @nosound                ;    Yes
  254.                                         ;    No
  255.         sub.w    #1,VBV(CountB)            ;    Play only channel B.
  256.         move.l    VBV(ChanB),A1            ;    comments same as for
  257.         move.l    #0x40404040,D1            ;    channel A above.
  258.         moveq.l    #22,D0
  259.  
  260.         move.l    D1,D2
  261.         add.l    (A1)+,D2
  262.         move.l    D2,(A0)+
  263. @vbBloop
  264.         move.l    D1,D2
  265.         add.l    (A1)+,D2
  266.         move.l    D2,(A0)+
  267.  
  268.         move.l    D1,D2
  269.         add.l    (A1)+,D2
  270.         move.l    D2,(A0)+
  271.         dbra    D0,@vbBloop
  272.  
  273.         move.l    A1,VBV(ChanB)
  274.         move.l    (SP)+,A5                ;    Restore A5
  275.         rts                                ;    Return from vbl routine
  276. @twosounds
  277.         sub.w    #1,VBV(CountB)            ;    Decrement channel B count
  278.         move.l    VBV(ChanB),A2            ;    A2 = channel B sound data pointer
  279.         move.w    #22,D0                    ;    ((23 * 8) + 4) bytes = 188 bytes
  280.  
  281.         move.l    (A1)+,D1                ;    Get Sound channel A
  282.         add.l    (A2)+,D1                ;    Add channel B
  283.         move.l    D1,(A0)+                ;    Store sound
  284.  
  285. @vbABloop
  286.         move.l    (A1)+,D1                ;    Get Sound channel A
  287.         add.l    (A2)+,D1                ;    Add channel B
  288.         move.l    D1,(A0)+                ;    Store sound
  289.  
  290.         move.l    (A1)+,D1                ;    Get Sound channel A
  291.         add.l    (A2)+,D1                ;    Add channel B
  292.         move.l    D1,(A0)+                ;    Store sound
  293.  
  294.         dbra    D0,@vbABloop            ;    Loop
  295.         move.l    A1,VBV(ChanA)            ;    Update sound channel A data pointer
  296.         move.l    A2,VBV(ChanB)            ;    Update sound channel B data pointer
  297.         move.l    (SP)+,A5                ;    Restore A5
  298.         rts                                ;    Return from vbl routine
  299. @nosound
  300.         move.l    #0x80808080,D1            ;    Silence
  301.         move.w    #46,D0                    ;    (45+1)*4 bytes of silence
  302. @silencer
  303.         move.l    D1,(A0)+                ;    Store silence
  304.         dbra    D0,@silencer            ;    loop
  305. @endvbl
  306.         move.l    (SP)+,A5                ;    Restore A5
  307.         rts                                ;    Return from vbl routine
  308. @mybase
  309.         dc.l    0                        ;    Vv record address stored here.
  310.     }
  311. }
  312.  
  313. /*
  314. >>    You should call CloseSoundKit before exiting your program.
  315. >>    The sound kit tries to make sure you do, but doing it yourself
  316. >>    will be more reliable. It should be possible to reopen the
  317. >>    sound kit after you have closed it. I haven't tried to do that.
  318. */
  319.  
  320. static    long    oldExit;
  321.  
  322. void    CloseSoundKit()
  323. {
  324.     if(Vv.SKOpen)
  325.     {
  326.         if(OldSound)
  327.         {    VRemove((void *)&Vv.VBL);
  328.             StopSound();
  329.         }
  330.         else
  331.         {    SndDisposeChannel(SKChannel,-1);
  332.         }
  333.  
  334.         SetSoundVol(OldVol);
  335.         DisposPtr(SKPtr);
  336.         NumSounds=0;
  337.         Vv.SKOpen=0;
  338.         NSetTrapAddress(oldExit,0x9F4,ToolTrap);
  339.     }
  340. }
  341.  
  342. /*
  343. >>    ExitToShell is patched to call this routine
  344. >>    to make sure that the kit is closed before the
  345. >>    program quits. Without this patch, forgetting to
  346. >>    close the sound kit and exiting the program generated
  347. >>    some interesting and exiting side-effects like
  348. >>    crashes and trashed memory locations.
  349. */
  350.  
  351. void    SoundExitToShell()
  352. {
  353.     CloseSoundKit();
  354.     asm    {    move.l    oldExit,A0
  355.             jmp        (A0)
  356.         }
  357. }
  358. /*
  359. >>    Patch exittoshell to make sure that vbl routine is removed.
  360. */
  361. void    ExitSoundPatch()
  362. {    
  363.     oldExit=NGetTrapAddress(0x9F4,ToolTrap);
  364.     NSetTrapAddress((long)SoundExitToShell,0x9F4,ToolTrap);
  365. }
  366. /*
  367. >>    Initialize FFSynthRec and start producing silence.
  368. */
  369. void    StartNoise()
  370. {
  371.     register    long    *p;
  372.     register    int        i;
  373.  
  374.     SoundBuf=(FFSynthPtr)NewPtr(700);    /*    Allocate buffer                    */
  375.     
  376.     p=(long *)SoundBuf;
  377.     for(i=700/4;i;i--)    *p++=0x80808080;/*    Store silence in buffer            */
  378.  
  379.     SoundBuf->mode=ffMode;                /*    Freeform (sampled) data            */
  380.     SoundBuf->count=FixRatio(1,2);        /*    11 Khz sampling rate            */
  381.  
  382.     Vv.SPar.ioRefNum=-4;                /*    Sound driver.                    */
  383.     Vv.SPar.ioBuffer=(Ptr)SoundBuf;        /*    FFSynthPtr stored here            */
  384.     Vv.SPar.ioReqCount=660;                /*    Play 660 bytes (At least)        */
  385.     Vv.SPar.ioCompletion=0;                /*    No ioCompletion routine.        */
  386.     Vv.SoundB=(void *)SoundBuf->waveBytes;/*    Store buffer start address        */
  387.     Vv.SoundP=0;                        /*    Start with buffer at offset 0    */
  388.  
  389.     PBWrite(&Vv.SPar,-1);                /*    Start playing                    */
  390. }
  391.  
  392. /*
  393. >>    SKVolume allows you to change the sound volume.
  394. >>    Note that all Macs are capable of 9 distinct
  395. >>    sound volumes. Volume 0 is usually understood
  396. >>    as silence, but actually it is just a low volume
  397. >>    setting. SKVolume reassigns these values so that
  398. >>    0 is really silence and 8 is the maximum volume.
  399. */
  400. void    SKVolume(vol)
  401. int        vol;
  402. {
  403.     if(vol>8) vol=8;
  404.     if(vol<0) vol=0;
  405.     Vv.volume=vol;
  406.     if(vol)
  407.     {    SetSoundVol(vol-1);
  408.         if(OldSound)
  409.             PBWrite(&Vv.SPar,-1);
  410.     }
  411.     else
  412.     {    Vv.CountA=0;
  413.         Vv.CountB=0;
  414.     }
  415. }
  416.  
  417. /*
  418. >>    Create a double[back] buffering data structure for
  419. >>    the sound manager.
  420. */
  421. SndDoubleBuffer    *SKCreateDBuffer()
  422. {
  423.     register    SndDoubleBuffer    *buf;
  424.     register    int                i;
  425.     register    char            *p;
  426.  
  427.     buf=(SndDoubleBuffer *)NewPtr(SKBUFFERSIZE+sizeof(SndDoubleBuffer));
  428.     buf->dbNumFrames=SKBUFFERBYTES;
  429.     buf->dbUserInfo[0]= (long)&Vv;
  430.     buf->dbFlags=dbBufferReady;
  431.     
  432.     p= buf->dbSoundData;
  433.     for(i=0;i<SKBUFFERSIZE;i++)
  434.     {    *p++= 128;
  435.     }
  436.     
  437.     return    buf;
  438. }
  439. void    InitSoundKit()
  440. {
  441.     int        err;
  442.     long    response;
  443.  
  444.     GetSoundVol((void *)&OldVol);
  445.     SKVolume(OldVol+1);
  446.     DeCompress();
  447.     DecodeSounds();
  448.  
  449.     ExitSoundPatch();
  450.  
  451.     if(Gestalt(gestaltSoundAttr, &response))
  452.     {    OldSound = 1;
  453.     }
  454.     else
  455.     {    if(response & (1 << (31 - gestaltSoundIOMgrPresent)))
  456.         {    OldSound = 1;
  457.         }
  458.     }
  459.  
  460.     if(OldSound)
  461.     {    StartNoise();
  462.         InstallMyVBL();
  463.     }
  464.     else
  465.     {
  466.         SKDouble.dbhNumChannels        =1;
  467.         SKDouble.dbhSampleSize        =8;
  468.         SKDouble.dbhCompressionID    =0;
  469.         SKDouble.dbhPacketSize        =0;
  470.         SKDouble.dbhSampleRate        =KHZ22;
  471.         
  472.         SKDouble.dbhBufferPtr[0]    =SKCreateDBuffer();
  473.         SKDouble.dbhBufferPtr[1]    =SKCreateDBuffer();
  474.         SKDouble.dbhDoubleBack        =(void *)SKDoubleBackRoutine;
  475.  
  476.         SKChannel=0;
  477.         err=SndNewChannel(&SKChannel,sampledSynth,4,0L);
  478.         err=SndPlayDoubleBuffer(SKChannel,&SKDouble);
  479.     }
  480.     Vv.SKOpen=-1;
  481. }
  482.  
  483. void    PlayA(num,priority)
  484. register    int        num,priority;
  485. {
  486.     if(Vv.volume)            /*    If volume is not off.                    */
  487.     if(num<NumSounds)        /*    And the sound number looks possible.    */
  488.     if(num>=0)
  489.     if(priority >= Vv.PriA || Vv.CountA==0)    /*    Can channel be used?    */
  490.     {    Vv.CountA=0;                        /*    Stop old sound.            */
  491.         Vv.ChanA=Sounds[num].Poin;            /*    Pointer to new sound.    */
  492.         Vv.CountA=Sounds[num].Count;        /*    Start new sound.        */
  493.         Vv.PriA=priority;                    /*    Store priority.            */
  494.     }
  495.     else                    /*    Try if the other channel is available.    */
  496.     {    if(Vv.CountB==0)
  497.         {    Vv.CountB=0;
  498.             Vv.ChanB=Sounds[num].Poin;
  499.             Vv.CountB=Sounds[num].Count;
  500.             Vv.PriB=0;
  501.         }
  502.     }
  503. }
  504. void    PlayB(num,priority)
  505. register    int        num,priority;
  506. {
  507.     if(Vv.volume)
  508.     if(num<NumSounds)
  509.     if(num>=0)
  510.     if(priority >= Vv.PriB || Vv.CountB==0)
  511.     {    Vv.CountB=0;
  512.         Vv.ChanB=Sounds[num].Poin;
  513.         Vv.CountB=Sounds[num].Count;
  514.         Vv.PriB=priority;
  515.     }
  516.     else
  517.     {    if(Vv.CountA==0)
  518.         {    Vv.CountA=0;
  519.             Vv.ChanA=Sounds[num].Poin;
  520.             Vv.CountA=Sounds[num].Count;
  521.             Vv.PriA=0;
  522.         }
  523.     }
  524. }
  525.  
  526. /*
  527. >>    SKProcessHandle allows normal sound sample handles
  528. >>    to be converted to a form suitable for the sound kit.
  529. */
  530. void    SKProcessHandle(thedata)
  531. Handle    thedata;
  532. {
  533.     register    unsigned    char    *source,*dest;
  534.     register    long                len,oldlen;
  535.     register    int                    counter;
  536.     register    int                    sampleframes,samplepad;
  537.     
  538.     if(OldSound)
  539.     {    sampleframes = 185;
  540.         samplepad = 188;
  541.     }
  542.     else
  543.     {    sampleframes = 512;
  544.         samplepad = 512;
  545.     }
  546.     
  547.     oldlen = GetHandleSize(thedata);
  548.     len = (oldlen + sampleframes - 1) / sampleframes * samplepad;
  549.     
  550.     SetHandleSize(thedata,len+sizeof(long));
  551.     
  552.     if(!MemErr)
  553.     {    BlockMove(*thedata,*thedata + len - oldlen + sizeof(long), oldlen);
  554.         dest = (unsigned char *)*thedata;
  555.         *(long *)dest = (oldlen + sampleframes - 1) / sampleframes;
  556.         dest += sizeof(long);
  557.         source = dest + len - oldlen;
  558.         counter = 0;
  559.         
  560.         while(oldlen--)
  561.         {    *dest++ = (*source++)>>1;
  562.             len--;
  563.             counter++;
  564.             
  565.             if(counter == sampleframes)
  566.             {    while(counter++ < samplepad)
  567.                 {    *dest++ = 64;
  568.                     len--;
  569.                 }
  570.                 counter = 0;
  571.             }
  572.         }
  573.         while(len--)
  574.         {    *dest++ = 64;
  575.         }
  576.     }
  577. }
  578.  
  579. /*
  580. >>    You can play a preprocessed handle with the
  581. >>    following two routines. Read the manual for
  582. >>    more information.
  583. */
  584. void    SKPlayHandleA(thehand,priority)
  585. register    Handle    thehand;
  586. register    int        priority;
  587. {
  588.     if(Vv.volume)
  589.     if(priority >= Vv.PriA || Vv.CountA==0)
  590.     {    Vv.CountA=0;
  591.         Vv.ChanA=*thehand+sizeof(long);
  592.         Vv.CountA=*(long *)*thehand;
  593.         Vv.PriA=priority;
  594.     }
  595.     else
  596.     {    if(Vv.CountB==0)
  597.         {    Vv.CountB=0;
  598.             Vv.ChanB=*thehand+sizeof(long);
  599.             Vv.CountB=*(long *)*thehand;
  600.             Vv.PriB=0;
  601.         }
  602.     }
  603. }
  604. void    SKPlayHandleB(thehand,priority)
  605. register    Handle    thehand;
  606. register    int        priority;
  607. {
  608.     if(Vv.volume)
  609.     if(priority >= Vv.PriB || Vv.CountB==0)
  610.     {    Vv.CountB=0;
  611.         Vv.ChanB=*thehand+sizeof(long);
  612.         Vv.CountB=*(long *)*thehand;
  613.         Vv.PriB=priority;
  614.     }
  615.     else
  616.     {    if(Vv.CountA==0)
  617.         {    Vv.CountA=0;
  618.             Vv.ChanA=*thehand+sizeof(long);
  619.             Vv.CountA=*(long *)*thehand;
  620.             Vv.PriA=0;
  621.         }
  622.     }
  623. }
  624.